<?php

 /**
  * @package JooS
  * @subpackage PHPackager
  */

  require_once "JooS/PHPackager/DOM/Element.php";

  class JooS_PHPackager_DOM_Element_Package extends JooS_PHPackager_DOM_Element {
    const EVENT_NEW_METHOD = "PHPackager.Package.newMethod";

    const EVENT_NEW_PROPERTY = "PHPackager.Package.newProperty";

    private $_propertiesNodes = null;
    
    private $_relationsNodes = null;

    private $_name = null;

    private $_version = null;

    private $_properties = array();

    private $_methods = array();

    /**
s     * @return JooS_PHPackager_DOM_Element_Package
     */
    public function make() {
      require_once "JooS/Syntax/Compiler.php";
      require_once "JooS/Syntax/PHPackager/DOM/Name.php";
      require_once "JooS/Syntax/PHPackager/DOM/Version.php";

      $name = $this->getNode()->getAttribute("name");
      $this->_name = JooS_Syntax_Compiler::newInstance( new JooS_Syntax_PHPackager_DOM_Name() )->compile( $name );
      if ($this->_name === false)
        self::throwException("Syntax error in project name: '$name'");

      $version = $this->getNode()->getAttribute("version");
      $this->_version = JooS_Syntax_Compiler::newInstance( new JooS_Syntax_PHPackager_DOM_Version() )->compile( $version );
      if ($this->_version === false)
        self::throwException("Syntax error in project version: '$version'");

      $this->_propertiesNodes = $this->query("node()[processing-instruction()]", "JooS_PHPackager_DOM_Element_Tasks");
      $this->_relationsNodes = $this->query("depends|provides|replaces|conflicts|breaks");

      foreach ($this->_propertiesNodes as $node)
        $node->make();

      $_unique = array();
      foreach ($this->_relationsNodes as $k => $node) {
        $name = $node->getNode()->tagName;
        if (!isset($_unique[$name])) {
          $node->make();
          $_unique[$name] = true;
        }
        else
          unset($this->_relationsNodes[$k]);
      }

      return $this;
    }

    /**
     * @param JooS_CodeGenerator_Method $method
     */
    public function addMethod(JooS_CodeGenerator_Method $method) {
      $this->_methods[] = $method;
    }

    /**
     * @param JooS_CodeGenerator_Property $property
     */
    public function addProperty(JooS_CodeGenerator_Property $property) {
      $this->_properties[] = $property;
    }

    /**
     * @return JooS_PHPackager_DOM_Element_Package
     */
    public function install() {
      require_once "JooS/Event.php";
      require_once "JooS/CodeGenerator/Property.php";
      require_once "JooS/CodeGenerator/Class.php";
      require_once "JooS/PHPackager/Manager.php";

      $Event_newMethod = JooS_Event::newInstance(self::EVENT_NEW_METHOD)
        ->clear()
        ->attach(array($this, "addMethod"))
        ->commit();

      $Event_newProperty = JooS_Event::newInstance(self::EVENT_NEW_PROPERTY)
        ->clear()
        ->attach(array($this, "addProperty"))
        ->commit();

      $className = "JooSX_Package_" . $this->_name . "_" . str_replace(".", "_", $this->_version);

      $Event_newProperty->notify(
        JooS_CodeGenerator_Property::newInstance("_name")
          ->setVisibility(JooS_CodeGenerator_Property::VISIBILITY_PROTECTED)
          ->setValue($this->_name)
          ->setStatic(true)
      );

      $Event_newProperty->notify(
        JooS_CodeGenerator_Property::newInstance("_version")
          ->setVisibility(JooS_CodeGenerator_Property::VISIBILITY_PROTECTED)
          ->setValue($this->_version)
          ->setStatic(true)
      );

      $pkgDoc = new DOMDocument("1.0", "UTF-8");
      $pkgDoc->loadXML("<control />");
      $pkgDoc->documentElement->appendChild( $pkgDoc->importNode($this->getNode(), true) );

      $Event_newProperty->notify(
        JooS_CodeGenerator_Property::newInstance("_control")
          ->setVisibility(JooS_CodeGenerator_Property::VISIBILITY_PROTECTED)
          ->setValue( trim($pkgDoc->saveXML()) )
          ->setStatic(true)
      );

      foreach ($this->_relationsNodes as $node)
        $node->install();
      foreach ($this->_propertiesNodes as $node)
        $node->install();

      $newClass = JooS_CodeGenerator_Class::newInstance($className)
        ->setExtendedClass("JooS_PHPackager_Instance");

      foreach ($this->_properties as $property)
        $newClass->addProperty($property);
      foreach ($this->_methods as $method)
        $newClass->addMethod($method);

      JooS_Event::newInstance(JooS_PHPackager_Manager::EVENT_PACKAGE_NEW_SOURCE)->notify($className, $newClass);

      $Event_newMethod->rollback();
      $Event_newProperty->rollback();

      return $this;
    }
  }
